package com.studerb.service.interfaces;

import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;

import com.studerb.exceptions.ServiceException;
import com.studerb.model.NewsGroup;
import com.studerb.tasks.interfaces.ITaskListener;

public interface INewsGroupService extends IService {

	/**
	 * Create a task to download all the NewsGroups (nntp list command).
	 * 
	 * @param taskListener
	 *            variable number of listeners to the task
	 * @throws ServiceException
	 * @see com.studerb.tasks.NewsGroups.ListCommandTask
	 */
	void downloadAllNewsGroups(ITaskListener... taskListeners) throws ServiceException;

	/**
	 * Fetch a newsgroup by its name (e.g. 'alt.binaries.boneless');
	 * 
	 * @param groupName
	 * @return NewsGroup
	 * @throws ServiceException
	 *             if no group with that name is found
	 */
	NewsGroup getByGroupName(String groupName) throws ServiceException;

	/**
	 * Gets a count of the number of headers a group has
	 * 
	 * @param group
	 * @return count of headers
	 * @throws ServiceException
	 *             if group doesn't exist
	 */
	int getHeaderCount(NewsGroup group) throws ServiceException;

	/**
	 * Obtains a non-singleton runnable object that is passed a queue from which
	 * the {@link com.studerb.tasks.newsGroups.ListCommandTask ListCommandTask}
	 * can efficiently save/modify/delete newsgroups via the 'list' nntp command
	 * <p>
	 * This could just be a method in the interface, but in order to speed
	 * things up we use a separate object that can keep state and avoid multiple
	 * transactions / database sessions
	 * 
	 * @param queue
	 *            that the ListCommandTask passes lines of text representing
	 *            newsgroups on the server
	 * @return callable object that the task can use to process.
	 * @see com.studerb.service.interfaces.INewsGroupService#getListCommandProcessor(java.util.concurrent.BlockingQueue)
	 */
	Callable<Void> getListCommandProcessor(BlockingQueue<String> queue);

	/**
	 * Returns the maximum article number of a header that has been downloaded
	 * using the xover command for the newsgroup parameter Implementations
	 * should return null if the newsgroup is not subscribed (has no downloaded
	 * headers stored).
	 * 
	 * @param newsGroup
	 * @return maximum article number stored or null if the newsgroup is
	 *         unknown, not subsribed, or has never had headers downloaded
	 */
	Long getMaxArticleNumber(NewsGroup newsGroup);

	/**
	 * Returns the minimum article number of a header that has been downloaded
	 * using the xover command for the newsgroup parameter Implementations
	 * should return null if the newsgroup is not subscribed (has no downloaded
	 * headers stored).
	 * 
	 * @param newsGroup
	 * @return minimum article number stored or null if the newsgroup is
	 *         unknown, not subsribed, or has never had headers downloaded
	 */
	Long getMinArticleNumber(NewsGroup newsGroup);

	/**
	 * Get a list of all NewsGroups. Header objects referenced by each newsgroup
	 * may or may not be initialized.
	 * 
	 * @return an umodifiable list of all the NewsGroups which should be in
	 *         sorted order according to the some comparator
	 */
	List<NewsGroup> getNewsGroups();

	/**
	 * Subscribes a newsgroup, which essentially allows its #{link
	 * com.studerb.model.NewsGroup.getHeaders getHeaders} method to be valid
	 * <p>
	 * Publishes a {@link com.studerb.events.NewsGroupEvent NewsGroupEvent} of
	 * type {@link com.studerb
	 * com.studerb.events.NewsGroupEvent.EventType.UPDATED UPDATED}.
	 * 
	 * @param group
	 *            NewsGroup to subscribe
	 * @throws ServiceException
	 *             if group doesn't exist or the newsgroup is not already
	 *             subscribed
	 */
	void subscribe(NewsGroup group) throws ServiceException;

	/**
	 * Unsubscribe a NewsGroup
	 * <p>
	 * Publishes a {@link com.studerb.events.NewsGroupEvent NewsGroupEvent} of
	 * type {@link com.studerb
	 * com.studerb.events.NewsGroupEvent.EventType.UPDATED UPDATED}.
	 * 
	 * @param group
	 *            Newsgroup to delete
	 * @throws ServiceException
	 *             if group doesn't exist or the newsgroup is not already
	 *             subscribed
	 */
	void unsubscribe(NewsGroup group) throws ServiceException;

	/**
	 * Update a modified newsgroup to the database.
	 * <p>
	 * Publishes a {@link com.studerb.events.NewsGroupEvent NewsGroupEvent} of
	 * type {@link com.studerb
	 * com.studerb.events.NewsGroupEvent.EventType.UPDATED UPDATED}.
	 * 
	 * @param newsGroup
	 * @throws ServiceException
	 */
	void updateNewsGroup(NewsGroup newsGroup) throws ServiceException;

}
